import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from scipy import stats


def smart_score_describe(df):
    """
    :param df:指定格式的dataframe
    :return: 智能描述性统计
    """
    # print(df)
    df = df.sort_values(by=df.columns[0])
    df = df.reset_index(drop=True)

    data = df.iloc[:, 1:].values

    # 计算原始的描述性统计数据
    data_means = data.mean(axis=0)
    data_stds = data.std(axis=0)

    # 均值加上/减去3倍标准差得到阈值
    threshold_upper = data_means + 3 * data_stds
    threshold_lower = data_means - 3 * data_stds

    # 将超过阈值的数据替换为 NaN，并记录其行号和列号
    rows, cols = np.where((data > threshold_upper) | (data < threshold_lower))
    data[rows, cols] = np.nan

    # 计算剔除 NaN 后的每列均值和方差
    smart_data_means = np.nanmean(data, axis=0)
    smart_data_stds = np.nanstd(data, axis=0)
    smart_data_quartiles = np.nanquantile(data, [0.25, 0.5, 0.75], axis=0)
    smart_data_skewness = stats.skew(data, axis=0)
    smart_data_kurtosis = stats.kurtosis(data, axis=0)

    # 输出描述性统计结果
    # print(describe_df)
    # 输出被剔除数据的行号和列号
    for i in range(len(rows)):
        print("异常成绩学生姓名：" + df.iloc[rows[i], 0] + "," + "该生异常考试：" + df.columns[cols[i] + 1])

    for i in range(len(data_means)):
        print("科目:", df.columns[i + 1])
        print("原始平均分和原始标准差为：", end='')
        print('{:.2f},{:.2f}'.format(data_means[i], data_stds[i]))
        print("智能平均分和智能标准差为：", end='')
        print('{:.2f},{:.2f}'.format(smart_data_means[i], smart_data_stds[i]))
        print("原始四分位分数为：", end='')
        print('{:.2f},{:.2f},{:.2f}'.format(smart_data_quartiles[0][i], smart_data_quartiles[1][i],
                                            smart_data_quartiles[2][i]))
        print("智能四分位分数为：", end='')
        print('{:.2f},{:.2f},{:.2f}'.format(smart_data_quartiles[0][i], smart_data_quartiles[1][i],
                                            smart_data_quartiles[2][i]))
        # print("原始偏度和峰度为：", end='')
        # print('{:.2f},{:.2f}'.format(data_skewness[i], data_kurtosis[i]))
        # print("智能偏度和峰度为：", end='')
        # print('{:.2f},{:.2f}'.format(smart_data_skewness[i], smart_data_kurtosis[i]))

    # 构造一个DataFrame保存描述性统计结果
    describe_df = pd.DataFrame({
        'subject': df.columns[1:],
        'mean': data_means,
        'std': data_stds,
        'smart_mean': smart_data_means,
        'smart_std': smart_data_stds
    })
    # 宋体牛逼
    plt.rcParams['font.family'] = ['STSong']

    # 绘制箱线图
    fig, ax = plt.subplots()
    sns.boxplot(data=data, orient='v', notch=True, ax=ax)
    ax.set_title('智能箱线图')
    ax.set_xlabel('科目')
    ax.set_ylabel('分数')

    # 绘制小提琴图
    fig, ax = plt.subplots()
    sns.violinplot(data=data, orient='v', inner='stick', ax=ax)
    ax.set_title('智能小提琴图')
    ax.set_xlabel('科目')
    ax.set_ylabel('分数')
    plt.show()

    return True


if __name__ == "__main__":
    df = pd.read_excel("../TestExample/test_score001.xlsx")
    smart_score_describe(df)
